﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using OrbitOne.CRMUpdater.CRM;
using OrbitOne.CRMUpdater.Properties;

namespace OrbitOne.CRMUpdater
{
    public partial class frmMain : Form
    {
        #region Delegates
        private delegate void DesignRowDelegate(string text, int row, int? column);
        #endregion

        #region Private variables
        private const string DIALOGFILTER = "CSV Files(*.CSV)|*.CSV|All files (*.*)|*.*";
        private readonly Color ErrorColor = Settings.Default.ErrorColor;
        private readonly Color EditedColor = Settings.Default.EditedColor;
        private readonly Color UploadedColor = Settings.Default.UploadedColor;
        private readonly List<Delimiter> fieldDelimiters = new List<Delimiter>
            {
                 new Delimiter{Text = "Comma", Char = ','},
                 new Delimiter{Text = "Column", Char = ':'},
                 new Delimiter{Text = "Tab", Char = '\t'},
                 new Delimiter{Text = "Semi-column", Char = ';'},
            };
        private readonly List<Delimiter> dataDelimiters = new List<Delimiter>
            {
                 new Delimiter{Text = "Double quote", Char = '\"'},
                 new Delimiter{Text = "Single quote", Char = '\''},
                 new Delimiter{Text = "None", Char = '\0'}
            };
        private Timer timer;
        private List<int> ChangedRows = new List<int>();
        #endregion

        #region Properties
        public Updator Updator { get; set; }
        public frmLoginScreen Initiator { get; set; }
        #endregion

        #region Constructor
        public frmMain()
        {
            InitializeComponent();
            colUpload.BackColor = UploadedColor;
            colEdit.BackColor = EditedColor;
            colError.BackColor = ErrorColor;
            ddlDataDelimiter.DisplayMember = ddlFieldDelimiter.DisplayMember = "Text";
            ddlDataDelimiter.ValueMember = ddlFieldDelimiter.ValueMember = "Char";
            ddlDataDelimiter.DataSource = dataDelimiters;
            ddlFieldDelimiter.DataSource = fieldDelimiters;
            ddlDataDelimiter.SelectedIndex = Settings.Default.DataDelimiter;
            ddlFieldDelimiter.SelectedIndex = Settings.Default.FieldDelimiter;
        }
        #endregion

        #region Event Handlers
        private void frmMain_Load(object sender, EventArgs e)
        {
            timer = new Timer
                        {
                            Interval = 500,
                            Enabled = true
                        };
            timer.Tick += timer_Tick;
            Updator.ErrorOccurred += Updator_ErrorOccurred;
            Updator.RowUploadCompleted += Updator_RowUploadCompleted;

            btnGet.Enabled = false;
            cboEntity.Items.AddRange(Updator.Entities.OrderBy(_ => _).ToArray());
        }

        private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            var dialogResult = MessageBox.Show("Do you want to exit " + Application.ProductName + "?",
                                               "Exit",
                                               MessageBoxButtons.YesNoCancel,
                                               MessageBoxIcon.Question);
            if (dialogResult == DialogResult.Yes)
            {
                try
                {
                    Settings.Default.FieldDelimiter = ddlFieldDelimiter.SelectedIndex;
                    Settings.Default.DataDelimiter = ddlDataDelimiter.SelectedIndex;
                    Settings.Default.ErrorColor = colError.BackColor;
                    Settings.Default.EditedColor = colEdit.BackColor;
                    Settings.Default.UploadedColor = colUpload.BackColor;
                    Settings.Default.Save();
                }
                finally
                {
                    Initiator.Dispose();
                }
            }
            else if (dialogResult == DialogResult.No)
            {
                Initiator.Show();
                Dispose();
            }
            else
            {
                e.Cancel = true;
            }
        }

        private void Updator_ErrorOccurred(object sender, UpdaterErrorEventArgs e)
        {
            DesignRow(e.Exception.Message, e.RowIndex, e.ColumnIndex);
        }
        void Updator_RowUploadCompleted(object sender, RowUploadCompletedEventArgs e)
        {
            DesignRow(e.Message, e.RowIndex, null);
        }

        private void timer_Tick(object sender, EventArgs e)
        {
            if (Updator.Finished)
            {
                timer.Stop();
                toolStripProgressBar1.Visible = false;
                toolStripProgressBar1.Enabled = false;
                toolStripStatusLabel1.Text = "";
                if (!Updator.Error)
                {
                    ChangedRows.Clear();
                }
                else if (Updator.ErrorCounter != -1)
                {
                    MessageBox.Show(string.Format("There where {0} errors", Updator.ErrorCounter), "Update", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
            }
            else
            {
                toolStripStatusLabel1.Text = Updator.Status;
            }
        }

        private void cboEntity_SelectedIndexChanged(object sender, EventArgs e)
        {
            btnGet.Enabled = false;
            btnLoadCsv.Enabled = false;
            cboQuery.Items.Clear();
            cboQuery.ValueMember = "SavedQueryXml";
            cboQuery.DisplayMember = "SavedQueryName";
            cboQuery.Items.AddRange(Updator.GetQueries(cboEntity.Text).ToArray());
            cboQuery.Enabled = cboQuery.Items.Count > 0;
            btnGet.Enabled = true;
            btnLoadCsv.Enabled = true;
            btnDelete.Enabled = true;
        }
        private void cboQuery_SelectedIndexChanged(object sender, EventArgs e)
        {
            btnGet.Enabled = !string.IsNullOrEmpty(cboQuery.Text);
            btnLoadCsv.Enabled = !string.IsNullOrEmpty(cboQuery.Text);
        }

        private void btnDelete_Click(object sender, EventArgs e)
        {
            var query = (QueryItem)cboQuery.SelectedItem;
            Updator.DeleteFromCrm(query, cboEntity.Text);
        }
        private void btnGet_Click(object sender, EventArgs e)
        {
            Grid.DataSource = null;
            QueryItem item = null;
            if (!string.IsNullOrEmpty(cboQuery.Text))
                item = (QueryItem)cboQuery.SelectedItem;
            var dt = Updator.GetRecords(item, cboEntity.Text);
            if (dt != null)
            {
                Grid.DataSource = dt;
                btnExport.Enabled = true;
                btnExportToCrm.Enabled = true;
                if (dt.Columns.Cast<DataColumn>().Any(c => c.ColumnName == "statecode") && dt.Columns.Cast<DataColumn>().Any(c => c.ColumnName == "statuscode"))
                    btnChangeStateInCrm.Enabled = true;
                else
                    btnChangeStateInCrm.Enabled = false;
            }
            else
            {
                MessageBox.Show("Query returned no data", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }
        private void btnLoadCsv_Click(object sender, EventArgs e)
        {
            var odlg = new OpenFileDialog
            {
                Filter = DIALOGFILTER,
                FilterIndex = 1
            };
            Grid.DataSource = null;
            if (odlg.ShowDialog() != DialogResult.Cancel)
            {
                try
                {
                    Cursor = Cursors.WaitCursor;
                    var sr = new StreamReader(odlg.FileName, System.Text.Encoding.UTF8);
                    var csv = sr.ReadToEnd();
                    sr.Close();
                    Grid.DataSource = csv.FromCsv((char)ddlDataDelimiter.SelectedValue,
                                                  (char)ddlFieldDelimiter.SelectedValue);
                    btnExport.Enabled = true;
                    btnExportToCrm.Enabled = true;
                    if (((DataTable)Grid.DataSource).Columns.Cast<DataColumn>().Any(c => c.ColumnName == "statecode")
                        && ((DataTable)Grid.DataSource).Columns.Cast<DataColumn>().Any(c => c.ColumnName == "statuscode"))
                        btnChangeStateInCrm.Enabled = true;
                    else
                        btnChangeStateInCrm.Enabled = false;
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                finally
                {
                    Cursor = Cursors.Default;
                }
            }
        }
        private void btnExport_Click(object sender, EventArgs e)
        {
            var sdlg = new SaveFileDialog
                           {
                               Filter = DIALOGFILTER,
                               OverwritePrompt = true,
                               FilterIndex = 1
                           };
            if (sdlg.ShowDialog() != DialogResult.Cancel)
            {
                try
                {
                    Cursor = Cursors.WaitCursor;
                    var csv = ((DataTable)Grid.DataSource).ToCsv((char)ddlDataDelimiter.SelectedValue,
                                                                 (char)ddlFieldDelimiter.SelectedValue);
                    var sw = new StreamWriter(sdlg.FileName, false, System.Text.Encoding.UTF8);
                    sw.Write(csv);
                    sw.Flush();
                    sw.Close();
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                finally
                {
                    Cursor = Cursors.Default;
                }
            }
        }
        private void btnExportToCrm_Click(object sender, EventArgs e)
        {
            try
            {
                toolStripProgressBar1.Visible = true;
                toolStripProgressBar1.Enabled = true;
                timer.Start();
                DataTable toUpload;
                if (ChangedRows.Count != 0)
                {
                    toUpload = new DataTable();
                    toUpload.Columns.AddRange(((DataTable)Grid.DataSource).Columns
                                                                          .Cast<DataColumn>()
                                                                          .Select(d => new DataColumn(d.ColumnName))
                                                                          .ToArray());
                    ((DataTable)Grid.DataSource).Rows
                                                 .Cast<DataRow>()
                                                 .Where((d, i) => ChangedRows.Contains(i))
                                                 .ToList()
                                                 .ForEach(r => toUpload.Rows.Add(r.ItemArray));
                }
                else
                {
                    toUpload = (DataTable)Grid.DataSource;
                }
                Grid.Rows.Cast<DataGridViewRow>()
                         .Where(d => d.DefaultCellStyle.BackColor == EditedColor)
                         .ToList()
                         .ForEach(d => d.DefaultCellStyle.BackColor = Color.White);
                Updator.UploadToCrm(toUpload, cboEntity.Text);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        private void btnChangeStateInCrm_Click(object sender, EventArgs e)
        {
            try
            {
                toolStripProgressBar1.Visible = true;
                toolStripProgressBar1.Enabled = true;
                timer.Start();
                DataTable toUpload;
                if (ChangedRows.Count != 0)
                {
                    toUpload = new DataTable();
                    toUpload.Columns.AddRange(((DataTable)Grid.DataSource).Columns
                                                                          .Cast<DataColumn>()
                                                                          .Select(d => new DataColumn(d.ColumnName))
                                                                          .ToArray());
                    ((DataTable)Grid.DataSource).Rows
                                                 .Cast<DataRow>()
                                                 .Where((d, i) => ChangedRows.Contains(i))
                                                 .ToList()
                                                 .ForEach(r => toUpload.Rows.Add(r.ItemArray));
                }
                else
                {
                    toUpload = (DataTable)Grid.DataSource;
                }
                Grid.Rows.Cast<DataGridViewRow>()
                   .Where(d => d.DefaultCellStyle.BackColor == EditedColor)
                   .ToList().ForEach(d => d.DefaultCellStyle.BackColor = Color.White);
                Updator.ChangeStateInCrm(toUpload, cboEntity.Text);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        private void ColorLabel_Click(object sender, EventArgs e)
        {
            var cd = new ColorDialog
            {
                AllowFullOpen = true,
                AnyColor = true,
                FullOpen = true
            };
            if (DialogResult.Cancel != cd.ShowDialog())
            {
                ((Label)sender).BackColor = cd.Color;
            }
        }

        private void Grid_CellValueChanged(object sender, DataGridViewCellEventArgs e)
        {
            Grid.Rows.Cast<DataGridViewRow>()
                         .Where(d => d.DefaultCellStyle.BackColor == UploadedColor)
                         .ToList()
                         .ForEach(d => d.DefaultCellStyle.BackColor = Color.White);

            if (!ChangedRows.Contains(e.RowIndex))
                ChangedRows.Add(e.RowIndex);
            Grid.Rows[e.RowIndex].DefaultCellStyle.BackColor = EditedColor;
        }
        #endregion

        #region Private methods
        private void DesignRow(string text, int row, int? column)
        {
            if (Grid.InvokeRequired)
            {
                Grid.Invoke(new DesignRowDelegate(DesignRow), text, row, column);
            }
            else
            {
                var index = row;
                if (ChangedRows != null && ChangedRows.Count > 0)
                    index = ChangedRows[row];

                if (column.HasValue)
                {
                    Grid.Rows[index].Cells[column.Value].ToolTipText = text;
                    Grid.Rows[index].Cells[column.Value].Style.BackColor = ErrorColor;
                }
                else
                {
                    Grid.Rows[index].Cells
                                    .Cast<DataGridViewCell>()
                                    .ToList().ForEach(c => c.ToolTipText += text);
                    Grid.Rows[index].DefaultCellStyle.BackColor = string.IsNullOrEmpty(text) ? UploadedColor : ErrorColor;
                }
            }
        }
        #endregion
    }
}
